package com.microcore.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.microcore.dao.mapper.AssertConditionMapper;
import com.microcore.entity.AssertCondition;
import com.microcore.service.asserts.condition.CompareCondition;
import com.microcore.service.asserts.impl.Assertor;
import com.microcore.service.asserts.impl.IAssert;
import com.microcore.service.asserts.model.AssertModel;
import com.microcore.service.asserts.model.AssertMessage;
import com.microcore.service.asserts.model.AssertResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author: Uaena
 * @Date: 2019/1/8 0008 17:06
 * @Version 1.0
 */
@Service("assertService")
public class AssertService {

    private static final Logger logger = LoggerFactory.getLogger(AssertService.class);

    @Autowired
    private AssertConditionMapper mapper;

    /**
     * Json断言判断
     *
     * @param json
     * @param expression
     * @return
     */
    public static AssertResult toAssert(String json, String expression) {
        AssertResult result = new AssertResult();
        List<AssertMessage> list = new ArrayList<>();
        try {
            Map<String, Object> values = JSONObject.parseObject(json, new TypeReference<Map<String, Object>>() {
            });
            List<AssertModel> conditions = JSON.parseArray(expression, AssertModel.class);
            if (null != conditions && conditions.size() > 0) {
            	for (AssertModel model : conditions) {
	                int condition = model.getCondition();
	                // 获取解析器
	                IAssert iAssert = getAssertorNewInstance(CompareCondition.getConditionByGroupAndIndex(model.getType(), condition));
	                // 通过conditions中的key递归寻找map中的值
	                Object value = getValueByMap(values, model.getKey());
	                boolean flag = iAssert.run(value, model);
	                if (!flag) {
	                    list.add(new AssertMessage(model, flag));
	                }
	            }
            	if (list.size() == 0) {
                    result.setSuccess(true);
                }
            }
            
        } catch (JSONException e) {
            logger.error("断言表达式格式异常", e);
        }
        result.setMessages(list);
        return result;
    }

    private static Object getValueByMap(Map<String, Object> values, String str) {
        String[] keys = str.split("\\.");
        Map<String, Object> tempMap = values;
        for (int i = 0; i < keys.length - 1; i++) {
            tempMap = (Map<String, Object>) tempMap.get(keys[i]);
        }
        Object value = tempMap.get(keys[keys.length - 1]);
        return value;
    }

    /**
     * 检查是否为json数组
     *
     * @param expression
     * @return
     */
    public static boolean isJsonArray(String expression) {
        try {
            JSON.parseArray(expression, AssertModel.class);
            return true;
        } catch (JSONException e) {
            logger.error("格式有误", e);
        }
        return false;
    }

    /**
     * 获取断言器实例
     *
     * @param assertor
     * @return
     */
    public static IAssert getAssertorNewInstance(Assertor assertor) {
        try {
            if (assertor.getiAssert() == null) {
                throw new NullPointerException("未指定相应的断言处理器");
            }
            return assertor.getiAssert().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        throw new NullPointerException("未找到断言处理器");
    }

    @Transactional
    public List<AssertCondition> getAssert(String fkId) {
        return mapper.selectByFK(fkId);
    }

    @Transactional
    public Integer addAssert(AssertCondition assertCondition) {

        return mapper.insertSelective(assertCondition);
    }

    @Transactional
    public Integer updataAssert(AssertCondition assertCondition) {
        return mapper.updateByPrimaryKeySelective(assertCondition);
    }

    @Transactional
    public Integer deleteAssert(String fkId) {

        return mapper.deleteByFK(fkId);
    }

}
